﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Deployment;
using System.Deployment.Application;
using System.Threading;
using System.Windows.Forms;
using System.ComponentModel;

namespace Library.UpdateCheck
{
	/// <summary>
	/// Updater class
	/// </summary>
	public class Updater
	{
		private enum UpdateStatuses
		{
			NoUpdateAvailable,
			UpdateAvailable,
			UpdateRequired,
			NotDeployedViaClickOnce,
			DeploymentDownloadException,
			InvalidDeploymentException,
			InvalidOperationException
		}
		public Updater()
		{
		}

		public void CheckForUpdatesNow()
		{
			BackgroundWorker bgWorker = new BackgroundWorker();
			bgWorker.DoWork += new DoWorkEventHandler(bgWorker_UpdateCheck);
			bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_UpdateCheckFinished);
			bgWorker.RunWorkerAsync();
		}

		/// <summary>
		/// Will be executed when works needs to be done
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		public void bgWorker_UpdateCheck(object sender, DoWorkEventArgs e)
		{
			UpdateCheckInfo info = null;

			// Check if the application was deployed via ClickOnce.
			if (!ApplicationDeployment.IsNetworkDeployed)
			{
				e.Result = UpdateStatuses.NotDeployedViaClickOnce;
				return;
			}

			ApplicationDeployment updateCheck = ApplicationDeployment.CurrentDeployment;

			try
			{
				info = updateCheck.CheckForDetailedUpdate();
			}
			catch (DeploymentDownloadException dde)
			{
				e.Result = UpdateStatuses.DeploymentDownloadException;
				return;
			}
			catch (InvalidDeploymentException ide)
			{
				e.Result = UpdateStatuses.InvalidDeploymentException;
				return;
			}
			catch (InvalidOperationException ioe)
			{
				e.Result = UpdateStatuses.InvalidOperationException;
				return;
			}

			if (info.UpdateAvailable)
				if (info.IsUpdateRequired)
					e.Result = UpdateStatuses.UpdateRequired;
				else
					e.Result = UpdateStatuses.UpdateAvailable;
			else
				e.Result = UpdateStatuses.NoUpdateAvailable;
		}

		/// <summary>
		/// Will be executed once it's complete...
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void bgWorker_UpdateCheckFinished(object sender, RunWorkerCompletedEventArgs e)
		{
			switch ((UpdateStatuses)e.Result)
			{
				case UpdateStatuses.NoUpdateAvailable:
					//MessageBox.Show("No update available.");
					break;
				case UpdateStatuses.UpdateAvailable:
					DialogResult dialogResult = MessageBox.Show("An update is available.\n\nPlease update this application now.", "Update Available", MessageBoxButtons.OKCancel);
					if (dialogResult == DialogResult.OK)
						UpdateApplication();
					break;
				case UpdateStatuses.UpdateRequired:
					MessageBox.Show("A required update is available.\n\nClick 'OK' to install this update now.", "Update Available", MessageBoxButtons.OK);
					UpdateApplication();
					break;
				case UpdateStatuses.NotDeployedViaClickOnce:
					//MessageBox.Show("This application is not updateable. (Updater Error: 4)", "Updater Message", MessageBoxButtons.OK);
					break;
				case UpdateStatuses.DeploymentDownloadException:
					MessageBox.Show("This application tried to check for an update, but the server could not be found. (Updater Error: 5)", "Updater Message", MessageBoxButtons.OK);
					break;
				case UpdateStatuses.InvalidDeploymentException:
					MessageBox.Show("The update service for this application is no longer valid. (Updater Error: 6)", "Updater Message", MessageBoxButtons.OK);
					break;
				case UpdateStatuses.InvalidOperationException:
					// Probably not a ClickOnce app
					MessageBox.Show("This application cannot be updated. (Updater Error: 7)", "Updater Message", MessageBoxButtons.OK);
					break;
				default:
					MessageBox.Show("(Updater Error: 8)", "Updater Message", MessageBoxButtons.OK);
					break;
			}
		}

		private void UpdateApplication()
		{
			try
			{
				ApplicationDeployment updateCheck = ApplicationDeployment.CurrentDeployment;
				updateCheck.Update();
				MessageBox.Show("The application has been upgraded and will now restart.", "Update Successful", MessageBoxButtons.OK);
				Application.Restart();
			}
			catch (DeploymentDownloadException dde)
			{
				MessageBox.Show("There was a problem installing an update for this application.\n\nPlease check your network connection and try again.\n\nPlease contact support if the problem persists.\n\n(Updater Error: 9) Details: " + dde, "Updater Message", MessageBoxButtons.OK);
				return;
			}
		}
	}
}